/**
 * $Id: Editor.js,v 1.17 2013/05/23 16:00:22 gaudenz Exp $
 * Copyright (c) 2006-2012, JGraph Ltd
 */
// Specifies if local storage should be used (eg. on the iPad which has no filesystem)
var useLocalStorage = (mxClient.IS_TOUCH || urlParams['storage'] == 'local') && typeof (localStorage) != 'undefined';
var fileSupport = window.File != null && window.FileReader != null && window.FileList != null;

// Specifies if connector should be shown on selected cells
var touchStyle = mxClient.IS_TOUCH || urlParams['touch'] == '1';

// Counts open editor tabs (must be global for cross-window access)
var counter = 0;

// Cross-domain window access is not allowed in FF, so if we
// were openaded from another domain then this will fail. 
try
{
    var op = window;

    while (op.opener != null && !isNaN(op.opener.counter))
    {
        op = op.opener;
    }

    // Increments the counter in the first opener in the chain
    if (op != null)
    {
        op.counter++;
        counter = op.counter;
    }
}
catch (e)
{
    // ignore
}

/**
 * Editor constructor executed on page load.
 */
Editor = function()
{
    mxEventSource.call(this);
    this.init();
    this.initStencilRegistry();
    //this.graph = new Graph();
    //this.outline = new mxOutline(this.graph);
    //this.outline.updateOnPan = true;
    //this.undoManager = this.createUndoManager();

    //mxLog.show();

    var meditor = new mxEditor();
    this.graph = new Graph;
    this.outline = new mxOutline(this.graph);
    this.outline.updateOnPan = true;
    this.undoManager = this.createUndoManager();
    this.status = '';
    meditor.layoutDiagram = true;
    meditor.maintainSwimlanes = true;
    meditor.layoutSwimlanes = true;
    // Contains the name which was used for the last save. Default value is null.
    this.filename = null;
    this.getOrCreateFilename = function()
    {
        return this.filename || mxResources.get('drawing', [counter]) + '.xml';
    };
    this.getFilename = function()
    {
        return this.filename;
    };
    // Sets the status and fires a statusChanged event
    this.setStatus = function(value)
    {
        this.status = value;
        this.fireEvent(new mxEventObject('statusChanged'));
    };
    // Returns the current status
    this.getStatus = function()
    {
        return this.status;
    };
    // Contains the current modified state of the diagram. This is false for
    // new diagrams and after the diagram was saved.
    this.modified = false;
    // Updates modified state if graph changes
    this.graphChangeListener = function()
    {
        this.modified = true;
    };
    this.graph.getModel().addListener(mxEvent.CHANGE, mxUtils.bind(this, function()
    {

        this.graphChangeListener.apply(this, arguments);
    }));


    //<editor-fold defaultstate="collapsed" desc="varables">


    var AllArrays = new Array();
    var darray = new Array();
    var myType = "swimlane";
    var G = this.graph;
    var addStatus = "0";
    var addFromStatus = "0";

    this.addFromStatus = "0";

    var statusFroupdatePostion = true;
    //</editor-fold>

    //<editor-fold defaultstate="collapsed" desc="Xml">


    this.saveXml = function(ui) {
        var TData = "";


        llevel = 0;

        TData = '<mxGraphModel page="1" pageHeight="2000" pageWidth="2000" pageScale="1" fold="1" connect="1" tooltips="1" guides="1" grid="1">\n<root>\n<mxCell id="1"/>\n';
        if (AllArrays != null && AllArrays.length > 0) {
            for (var i = 0; i <= AllArrays.length; i++) {
                if (AllArrays[i] != null && AllArrays[i] != "") {

                    var tharray = AllArrays[i];
                    var CE = G.getModel().getCell(tharray[0]);
                    var cgao = CE.getGeometry();

                    if (CE.getParent().getId() == "1") {


                        TData = TData + '<swimlane style="' + CE.style + '"  id="' + tharray[0] + '" numCol="' + AllArrays[i].length + '" colType="actor" parent="1"><geometry posX="' + cgao.x + '" posY="' + cgao.y + '" width="' + cgao.width + '" height="' + cgao.height + '" />\n';
                        for (var c = 0; c <= tharray.length; c++) {
                            if (tharray[c] != null && tharray[c] != "") {
                                var CC = G.getModel().getCell(tharray[c]);
                                var ccgao = CC.getGeometry();

                                var Item = "";

                                var myname = CC.getAttribute('label', '-1');

                                if (CC.getAttribute('itemid', '-1') != '-1') {

                                    Item = " itemid=\"" + CC.getAttribute('itemid', '-1') + "\"  ";

                                }


                                TData = TData + '<column  ' + Item + '  posX="' + ccgao.x + '" posY="' + ccgao.y + '" headerStyle="' + CC.style + '" id="' + CC.getId() + '" index="' + c + '"  level="0" name="' + myname + '" width="' + ccgao.width + '" headerHeight="25"/>\n';

                                TData = TData + getchSwim(CC.getId());
                            }
                        }

                        TData = TData + '</swimlane>\n';
                    }
                }
            }

        }



        if (AllArrays != null && AllArrays.length > 0) {
            for (var i = 0; i <= AllArrays.length; i++) {
                if (AllArrays[i] != null && AllArrays[i] != "") {

                    var tharray = AllArrays[i];
                    for (var c = 0; c <= tharray.length; c++) {
                        if (tharray[c] != null && tharray[c] != "") {

                            var CE = G.getModel().getCell(tharray[c]);
                            TData += getxmlcellsC(CE);
                        }
                    }
                }
            }

        }

        TData += getxmlcellsC(G.getDefaultParent());

        TData += '</root></mxGraphModel>';

        return TData;
    }


    var llevel = 0;




    var myLeve = 0;
    function getLeve(m, cell) {




        if (m.getParent(cell) != null) {
            myLeve++;
            getLeve(m.getParent(cell));

        }


        return myLeve;

    }
    function getchSwim(parent) {

        myLeve = 0;
        var p = G.getModel().getCell(parent);


        var cells = G.getChildCells(p, true, true);

        var TData = "";









        for (var i = 0; i < cells.length; i++) {



            if (isSwimLane(cells[i])) {

                llevel = getLeve(G.getModel(), cells[i]) - 2;

                var CC = cells[i];
                var ccgao = CC.getGeometry();

                var myname = CC.getAttribute('label', '-1');
                var Item = "";
                if (CC.getAttribute('itemid', '-1') != '-1') {

                    Item = " itemid=\"" + CC.getAttribute('itemid', '-1') + "\"  ";

                }
                TData = TData + '<column ' + Item + ' posX="' + ccgao.x + '" posY="' + ccgao.y + '" headerStyle="' + CC.style + '" id="' + CC.getId() + '" index="' + i + '" level="' + (llevel) + '" name="' + myname + '" width="' + ccgao.width + '" headerHeight="25"   parentColumn="' + parent + '"  />';

                TData = TData + getchSwim(CC.getId());
            }
        }
        return TData;
    }


    function getxmlcellsC(Parent) {
        var TData = "";
        var cells = G.getChildCells(Parent, true, true);

        for (var i = 0; i <= cells.length; i++) {

            if (G.getModel().isVertex(cells[i])) {
                if (!isSwimLane(cells[i])) {

                    var CC = cells[i];
                    var ccgao = CC.getGeometry();


                    var myname = CC.getAttribute('label', '-1');

                    var Item = "";
                    if (CC.getAttribute('itemid', '-1') != '-1') {

                        Item = " itemid=\"" + CC.getAttribute('itemid', '-1') + "\"  ";

                    }


                    TData += '<mxCell  ' + Item + ' id="' + CC.getId() + '"  value="' + myname + '"     style="' + CC.style + '"  parent="' + CC.getParent().getId() + '" vertex="1"><mxGeometry  width="' + ccgao.width + '"  height="' + ccgao.height + '" y="' + ccgao.y + '" x="' + ccgao.x + '"  as="geometry" /></mxCell>';
                }
            } else if (G.getModel().isEdge(cells[i])) {
                var CC = cells[i];
                TData += '<mxCell id="' + CC.getId() + '"  value="' + CC.getValue() + '"   target="' + CC.target.getId() + '" source="' + CC.source.getId() + '"  style="' + CC.style + '"  parent="' + CC.getParent().getId() + '"  edge="1"><mxGeometry    as="geometry" /></mxCell>';


            }

        }

        return TData;
    }






    /*
     var parseXml;
     if (typeof window.DOMParser != "undefined") {
     parseXml = function(xmlStr) {
     return (new window.DOMParser()).parseFromString(xmlStr, "text/xml");
     };
     } else if (typeof window.ActiveXObject != "undefined" &&
     new window.ActiveXObject("Microsoft.XMLDOM")) {
     parseXml = function(xmlStr) {
     var xmlDoc = new window.ActiveXObject("Microsoft.XMLDOM");
     xmlDoc.async = "false";
     xmlDoc.loadXML(xmlStr);
     return xmlDoc;
     };
     } else {
     throw new Error("No XML parser found");
     }
     
     
     
     this.readvXml = function(xmlData) {
     
     
     
     
     var xml = parseXml('<data>' + xmlData + '</data>');
     var data = xml.getElementsByTagName("data")[0];
     
     
     
     
     var updatedata = '';
     
     if (data) {
     var dataNodes = data.childNodes;
     if (dataNodes) {
     
     
     
     for (var i = 0; i < dataNodes.length; i++) {
     var sty = dataNodes[i].getAttribute("style");
     if (sty != null) {
     var s = sty.split(";");
     if ("swimlane" != s[1]) {
     
     var mid = dataNodes[i].getAttribute("id");
     var chname = dataNodes[i].getAttribute("value");
     var pid = dataNodes[i].getAttribute("parent");
     var chwidth = dataNodes[i].childNodes[0].getAttribute("width");
     var chHeight = dataNodes[i].childNodes[0].getAttribute("height");
     var chX = dataNodes[i].childNodes[0].getAttribute("x");
     var chY = dataNodes[i].childNodes[0].getAttribute("y");
     
     
     
     var sty = dataNodes[i].getAttribute("style");
     var edge = dataNodes[i].getAttribute("edge");
     if (edge != null && edge == "1") {
     
     
     var target = dataNodes[i].getAttribute("target");
     var source = dataNodes[i].getAttribute("source");
     
     updatedata += '<mxCell id="' + mid + '" value="' + chname + '" style="' + sty + '" source="' + source + '" target="' + target + '" edge="1" parent="' + pid + '" ><mxGeometry  relative="1" as="geometry"/></mxCell>';
     
     
     
     
     } else {
     
     
     updatedata += '<mxCell id="' + mid + '" value="' + chname + '" style="' + sty + '" vertex="1" parent="' + pid + '" ><mxGeometry x="' + chX + '" y="' + chY + '" width="' + chwidth + '" height="' + chHeight + '" as="geometry"/></mxCell>';
     
     
     }
     
     
     }
     
     }
     
     }
     
     
     
     
     
     
     
     
     for (var i = 0; i < dataNodes.length; i++) {
     var sty = dataNodes[i].getAttribute("style");
     
     
     if (sty != null) {
     var s = sty.split(";");
     
     
     if ("swimlane" != s[1]) {
     
     var mid = dataNodes[i].getAttribute("id");
     var pid = dataNodes[i].getAttribute("parent");
     
     var target = dataNodes[i].getAttribute("target");
     var source = dataNodes[i].getAttribute("source");
     
     }
     
     }
     
     }
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     }
     }
     
     return  updatedata;
     }
     
     
     
     this.readXML = function(xmlData) {
     
     
     var updatedata = '<mxGraphModel grid="1" guides="1" tooltips="1" connect="1" fold="1" page="0" pageScale="1" pageWidth="826" pageHeight="1169"><root><mxCell id="0"/><mxCell id="1" parent="0"/>';
     
     var xml = parseXml(xmlData);
     
     var data = xml.getElementsByTagName("root")[0];
     
     if (data) {
     var dataNodes = data.childNodes;
     
     
     if (dataNodes) {
     
     for (var i = 0; i < dataNodes.length; i++) {
     
     
     
     var st = dataNodes[i].getAttribute("style");
     //   var colour = dataNodes[i].getAttribute("colour");
     
     if (st != null) {
     var s = st.split(";");
     if ("swimlane" == s[1]) {
     
     
     var dataColNodes = dataNodes[i].childNodes;
     
     var getId = dataNodes[i].getAttribute("id");
     var chHeight = dataNodes[i].childNodes[0].getAttribute("height");
     var paWidth = dataNodes[i].childNodes[0].getAttribute("height");
     var pX = dataNodes[i].childNodes[0].getAttribute("posX");
     var chY = dataNodes[i].childNodes[0].getAttribute("posY");
     //    getId = createArray();
     
     if (dataColNodes) {
     
     
     for (var c = 0; c < dataColNodes.length; c++) {
     var sty = dataColNodes[c].getAttribute("style");
     
     if (sty != null) {
     
     
     var st = sty.split(";");
     if ("swimlane" == st[1]) {
     
     var mid = dataColNodes[c].getAttribute("id");
     var chwidth = dataColNodes[c].getAttribute("width");
     
     var chX = dataColNodes[c].getAttribute("posX");
     var pid = dataColNodes[c].getAttribute("parent");
     var chname = dataColNodes[c].getAttribute("name");
     
     updatedata += '<mxCell id="' + mid + '" value="' + chname + '" style="' + sty + '" vertex="1" parent="' + pid + '" ><mxGeometry x="' + chX + '" y="' + chY + '" width="' + chwidth + '" height="' + chHeight + '" as="geometry"/></mxCell>';
     
     
     
     
     }
     }
     
     }
     
     
     
     
     
     }
     
     
     
     }
     
     
     
     }
     
     }
     
     updatedata += this.readvXml(xmlData);
     
     updatedata += '</root></mxGraphModel>';
     
     
     }
     }
     
     return updatedata;
     }*/
//xml
//</editor-fold>

//<editor-fold defaultstate="collapsed" desc="ArrayData">

    function getparentArrya(cell) {

        var returnData = null;
        var thg = cell.getGeometry();
        var cells = G.getChildCells(G.getDefaultParent(), true, true);
        for (var i = 0; i < cells.length; i++) {
            var cgao = cells[i].getGeometry();
            var ix = cgao.x + cgao.width;
            if (ix == thg.x) {

                returnData = getCellArray(cells[i].getId());
            }



        }




        return returnData;
    }

    function isInCellArray(id) {
        var returnArray = false;
        if (AllArrays != null && AllArrays.length > 0) {



            for (var i = 0; i <= AllArrays.length; i++) {
                if (AllArrays[i] != null) {
                    if (AllArrays[i].indexOf(id) >= 0) {
                        returnArray = true;
                    }
                }
            }

        }
        return returnArray;
    }

    function getCellArray(id) {
        var returnArray = null;
        if (AllArrays != null && AllArrays.length > 0) {
            for (var i = 0; i < AllArrays.length; i++) {
                if (AllArrays[i].indexOf(id) >= 0) {
                    returnArray = [i];
                }
            }
        }
        return returnArray;
    }
    function clearArray(id) {
        AllArrays = [];

    }
    function createArray() {
        AllArrays.push(new Array());
        return  AllArrays.length - 1;
    }

    function updateArray(id) {

        if (AllArrays[getCellArray(id)] != null) {


            darray = AllArrays[getCellArray(id)];
        }




    }
    function reNewArray2() {

        var returnArray = false;
        if (AllArrays != null && AllArrays.length > 0) {


            for (var i = 0; i <= AllArrays.length; i++) {
                if (AllArrays[i] != null) {

                    // var thCell = G.getModel().getCell(darray[i]);



                    for (var s = 0; s < AllArrays[i].length; s++) {


                        var myID = AllArrays[i][s];

                        var thCell = G.getModel().getCell(myID);

                        if (thCell == null) {
                            returnArray = true;

                            AllArrays[i].splice(AllArrays[i].indexOf(myID), 1);

                        }

                    }






                }
            }

        }
        return returnArray;
    }
    function removeFromArray(id) {


        var returnArray = false;
        if (AllArrays != null && AllArrays.length > 0) {



            for (var i = 0; i <= AllArrays.length; i++) {
                if (AllArrays[i] != null) {

                    if (AllArrays[i].indexOf(id) >= 0) {
                        returnArray = true;
                        AllArrays[i].splice(AllArrays[i].indexOf(id), 1);
                        // AllArrays[pArray].splice(AllArrays[pArray].length, 0, addcell.getId());

                    }
                }
            }

        }
        return returnArray;
    }
//</editor-fold>

//<editor-fold defaultstate="collapsed" desc="Type">

    function isSwimLane(cell) {


        if (cell != null) {
            if (cell.style != null) {

                var s = cell.style.split(";");

                for (var i = 0; i < s.length; i++) {
                    if (s[i] == myType) {


                        return true;
                        break;


                    }
                    ;



                }




            }
        }


    }
    function isclear(parent) {
        var chCelles = G.getChildVertices(parent);
        var returnData = true;


        if (parent != null) {
            if (parent.getId() != 1) {


                for (var i = 0; i < chCelles.length; i++) {
                    if (!isSwimLane(chCelles[i])) {

                        returnData = false;

                    }


                }
            }

        }

        return returnData;
    }

    this.isSwimLane = function(cell) {


        if (cell != null) {
            if (cell.style != null) {

                var s = cell.style.split(";");

                for (var i = 0; i < s.length; i++) {
                    if (s[i] == myType) {


                        return true;
                        break;


                    }
                    ;



                }



            }
        }

    }

    function getSwimType(cell) {

        if (cell != null) {
            if (cell.style != null) {

                var s = cell.style.split(";");



                return s[1];
            }
        }

    }

    function getSwimType2(cell) {

        if (cell != null) {
            if (cell.style != null) {

                var s = cell.style.split(";");



                return s[2];
            }
        }

    }



    this.isSwimHorizontal = function(cell) {
        var returnData = false;

        if (getSwimType(cell) == "horizontal=0" || getSwimType2(cell) == "horizontal=0") {

            returnData = true;
        }
        return returnData;

    }



    function isSwimHorizontal(cell) {
        var returnData = false;

        if (getSwimType(cell) == "horizontal=0" || getSwimType2(cell) == "horizontal=0") {

            returnData = true
        }
        return returnData;

    }
//</editor-fold>

//<editor-fold defaultstate="collapsed" desc="Utiles">

    function updatePostioncelles(celles) {
        for (var i = 0; i < celles; i++) {
            updatePostion(celles[i]);

        }

    }

    function updatePostion(cell) {


        if (statusFroupdatePostion) {

            if (cell != null) {
                if (cell.parent != null) {




                    if (!isSwimLane(cell) && cell.parent.getId() != "1") {
                        var cgao = cell.getGeometry();
                        var pgao = cell.parent.getGeometry();
                        if (cgao.x < 0) {
                            cgao.x = 0;
                            G.getModel().setGeometry(cell, cgao);
                        }

                        if (cgao.y < 0) {
                            cgao.y = 0;
                            G.getModel().setGeometry(cell, cgao);
                        }

                        if (cgao.x + cgao.width > pgao.width) {
                            cgao.x = (pgao.width) - cgao.width;
                            G.getModel().setGeometry(cell, cgao);
                        }



                        if (cgao.y + cgao.height > pgao.height) {

                            cgao.y = (pgao.height) - cgao.height;
                            G.getModel().setGeometry(cell, cgao);
                        }


                    }
                }
            }
        }
    }

    function RESIZEDUpdate(cell) {







        var cgao = cell.getGeometry();

        var x = cgao.x;
        var y = cgao.y;
        var width = cgao.width;
        var height = cgao.height;



        var cells = G.getChildCells(cell, true, true);

        for (var i = 0; i < cells.length; i++) {
            if (cells[i] != null) {
                if (G.getModel().isVertex(cells[i]))
                {
                    var cgch = cells[i].getGeometry();

                    var chw = parseInt(cgch.width) + parseInt(cgch.x);
                    var chh = parseInt(cgch.height) + parseInt(cgch.y);

                    if (chw > width) {

                        width = chw;

                    }

                    if (chh > height) {

                        height = chh;

                    }


                }





            }
        }



        for (var i = 0; i < darray.length; i++) {
            if (darray[i] != null)
            {
                var thCell = G.getModel().getCell(darray[i]);



                var cellsd = G.getChildCells(thCell, true, true);


                //  alert(cellsd.length);
                for (var s = 0; s < cellsd.length; s++) {
                    if (cellsd[s] != null) {
                        if (G.getModel().isVertex(cellsd[s]))
                        {
                            var cgch = cellsd[s].getGeometry();

                            var chw = parseInt(cgch.width) + parseInt(cgch.x);
                            var chh = parseInt(cgch.height) + parseInt(cgch.y);


                            if (isSwimHorizontal(thCell)) {

                                if (chw > width) {

                                    width = chw;

                                }


                            } else {

                                if (chh > height) {

                                    height = chh;

                                }


                            }



                        }





                    }
                }


            }
        }












        cgao.x = x;
        cgao.y = y;
        cgao.width = width;
        cgao.height = height;

        cell.setGeometry(cgao);

    }


    function reomveStyleAttr(cell, attr) {

        var d = "";
        if (cell != null) {
            if (cell.style != null) {

                var s = cell.style.split(";");
                //  alert(attr);
                for (var i = 0; i < s.length; i++) {

                    var e = s[i].split("=");

                    if (attr != e[0]) {
                        d += s[i] + ";";


                    }


                }
            }
        }


        return d.replace(";;", ";");
        ;
    }
    function getStyleAttr(cell, attr) {



        if (cell != null) {
            if (cell.style != null) {

                var s = cell.style.split(";");
                //  alert(attr);
                for (var i = 0; i < s.length; i++) {

                    var e = s[i].split("=");

                    if (attr == e[0]) {
                        return e[1];
                        break;

                    }


                }
            }
        }


    }






    function swimCllesUpdateSize(cell) {
        editor.disableUndo = 1;
        //updateCellChledrens(cell);
        if (isSwimLane(cell)) {



            var ge = cell.getGeometry();
            var ge = G.getModel().getCell(darray[0]).getGeometry();

            for (var i = 0; i < darray.length; i++) {
                if (darray[i] != null)
                {
                    var thCell = G.getModel().getCell(darray[i]);

                    if (thCell != null) {

                        if (i == 0) {


                            if (getStyleAttr(thCell, "movable") == "0") {

                                G.getModel().setStyle(thCell, reomveStyleAttr(thCell, "movable") + ';movable=1');



                            }

                        } else {

                            if (getStyleAttr(thCell, "movable") == "1") {

                                G.getModel().setStyle(thCell, reomveStyleAttr(thCell, "movable") + ';movable=0');

                            }
                        }




                    }
                    if (thCell != null && isSwimLane(thCell)) {
                        var thg = thCell.getGeometry();



                        if (isSwimHorizontal(cell)) {
                            thg.width = ge.width;
                            thg.x = ge.x;
                        } else {
                            thg.height = ge.height;
                            thg.y = ge.y;
                        }
                        G.getModel().setGeometry(thCell, thg);
                        updateCellChledrens(thCell);
                    }




                } else {

                    removeFromArray(darray[i]);


                }




            }



            swimCllesMerge();
        }
        editor.disableUndo = 0;
    }

    function swimCllesOrder() {
        editor.disableUndo = 1;
        var newArray = new Array();
        for (var i = 0; i <= darray.length; i++) {
            if (darray[i] != null)
            {
                var thCell = G.getModel().getCell(darray[i]);
                if (thCell != null && isSwimLane(thCell)) {
                    var thg = thCell.getGeometry();
                    //     newArray[darray[i]] = thg.x;
                    var myx = thg.x;
                    newArray.push({'A': myx, 'B': darray[i]});
                }
            }
            //unshift
            editor.disableUndo = 0;


        }
        newArray.sort(function(a, b) {
            return a.A - b.A;
        });
        var A = [];
        var B = [];
        for (var i = 0; i < newArray.length; i++) {
            A.push(newArray[i].A);
            B.push(newArray[i].B);
        }
        return B;
    }

    function swimCllesMerge() {

        editor.disableUndo = 1;

        for (var i = 0; i <= darray.length; i++) {


            if (i != 0) {

                if (darray[i] != null)
                {


                    var thCell = G.getModel().getCell(darray[i]);
                    if (thCell != null) {

                        if (isSwimHorizontal(thCell)) {


                            editor.disableUndo = 1;
                            var Bgeo = G.getModel().getCell(darray[i - 1]).getGeometry();
                            var THgeo = thCell.getGeometry();
                            THgeo.x = Bgeo.x;
                            THgeo.y = Bgeo.y + Bgeo.height;

                            G.getModel().setGeometry(thCell, THgeo);
                            editor.disableUndo = 0;



                        } else {

                            var tcell = G.getModel().getCell(darray[i - 1]);
                            if (tcell != null) {


                                var Bgeo = tcell.getGeometry();
                                var THgeo = thCell.getGeometry();
                                THgeo.x = Bgeo.x + Bgeo.width;
                                THgeo.y = Bgeo.y;
                                G.getModel().setGeometry(thCell, THgeo);
                            } else {

                                removeFromArray(darray[i - 1]);
                            }
                        }
                    } else {

                        removeFromArray(darray[i]);


                    }
                } else {
                    removeFromArray(darray[i]);

                }
            }

        }

        G.refresh();
        editor.disableUndo = 0;
    }

    function updateCellChledrens(cell) {
        editor.disableUndo = 1;
        if (cell != null) {
            var chCelles = G.getChildVertices(cell);



            if (cell.getId() != 1) {
                if (chCelles.length > 0) {

                    var Pgeo = cell.getGeometry();
                    var chwidth = Pgeo.width / chCelles.length;
                    var chheight = Pgeo.height / chCelles.length;
                    var num = 0;
                    for (var i = 0; i < chCelles.length; i++) {
                        if (isSwimLane(chCelles[i])) {

                            var thgeo = chCelles[i].getGeometry();
                            thgeo.y = 25;
                            var pArray = getCellArray(chCelles[i].getId());
                            var inx = num;
                            if (AllArrays[pArray] != null) {
                                inx = AllArrays[pArray].indexOf(chCelles[i].getId());
                            }
                            if (isSwimHorizontal(chCelles[i])) {

                                editor.disableUndo = 1;
                                thgeo.y = inx * chheight;
                                thgeo.x = 20;
                                num++;
                                thgeo.width = Pgeo.width - 20;
                                thgeo.height = chheight;
                                G.getModel().setGeometry(chCelles[i], thgeo);

                                editor.disableUndo = 0;


                            } else {
                                editor.disableUndo = 1;
                                thgeo.x = inx * chwidth;
                                thgeo.y = 20;
                                num++;
                                thgeo.width = chwidth;
                                thgeo.height = Pgeo.height - 20;
                                G.getModel().setGeometry(chCelles[i], thgeo);
                                editor.disableUndo = 0;

                            }

                            updatePostioncelles(G.getChildVertices(chCelles[i]));
                        } else {

                            updatePostion(chCelles[i]);

                        }
                    }

                    for (var i = 0; i < chCelles.length; i++) {

                        if (isSwimLane(chCelles[i])) {

                            updateCellChledrens(chCelles[i]);

                        }
                    }
                }
            }

        }

        editor.disableUndo = 0;
        G.refresh();
    }

    function updateChSize(cell) {
        editor.disableUndo = 1;
        if (cell != null) {

            swimCllesUpdateSize(cell);
            var pCell = cell.parent;
            updateCellChledrens(pCell);
        }

        editor.disableUndo = 0;
    }

    function UdateCellse(cell) {
        editor.disableUndo = 1;
        updateArray(cell.getId());
        updateChSize(cell);
        swimCllesMerge();
        editor.disableUndo = 0;
    }

    this.updateDataArray = function(Parent) {

        var cells = G.getChildCells(Parent, true, true);

        //   alert(AllArrays);



        for (var i = 0; i < cells.length; i++) {
            if (G.getModel().isVertex(cells[i])) {
                AddCellArry(cells[i]);
            }
        }



        for (var i = 0; i < cells.length; i++) {


            this.updateDataArray(cells[i]);
        }

    }


    G.convertValueToString = function(cell)
    {
        if (mxUtils.isNode(cell.value))
        {
            return cell.getAttribute('label', '');
        }
    };


    function  returnSwimStyle(ecall) {
        var morestyle = "";
        if (isSwimHorizontal(ecall)) {

            morestyle = ";horizontal=0;startSize=20";
        }
        return "shape=swimlane;swimlane" + morestyle + ";strokeColor=#0000FF;gradientColor=#9999FF;movable=0";

    }

    this.createV = function(parent, id, value, x, y, width, height, style) {

        try
        {

            var doc = mxUtils.createXmlDocument();
            var person1 = doc.createElement('AllCell');
            person1.setAttribute('itemid', '1');
            person1.setAttribute('label', 'Lane');
            var c = G.insertVertex(parent, id, person1, x, y, width, height, style);
        }
        finally
        {

        }
        return  c;
    }




    function arrayChek() {


        for (var i = 0; i < darray.length; i++) {



            var thCell = G.getModel().getCell(darray[i]);

            if (thCell == null) {


                var i = darray.indexOf(darray[i]);
                if (i != -1) {
                    darray.splice(i, 1);
                }


            }

        }
    }






    this.reupdateDataArray = function() {


        var s = darray;
        reNewArray2();





        this.updateDataArray(G.getModel().getParent());
        var cells = G.getChildCells(G.getModel().getParent(), true, true);

        for (var i = 0; i < cells.length; i++) {

            updateArray(cells[0].getId());

            arrayChek();

        }


        darray = s;

        arrayChek();


        for (var i = 0; i < cells.length; i++) {




            swimCllesUpdateSize(cells[i]);

            updateCellChledrens(cells[i]);


        }


    }

//</editor-fold>

//<editor-fold defaultstate="collapsed" desc="Actions">

    function swimCllesCollapse(status) {

        for (var i = 0; i <= darray.length; i++) {

            if (darray[i] != null)
            {
                var thCell = G.getModel().getCell(darray[i]);
                thCell.setCollapsed(status);
            }



        }
        G.refresh();
    }

    this.swimToRight = function() {
        var cells = G.getSelectionCells();
        var thisCell = cells[0];
        if (isSwimLane(thisCell)) {

            var thCell = thisCell.getId();
            var pArray = getCellArray(thCell);
            var inx = AllArrays[pArray].indexOf(thCell);
            if (inx < AllArrays[pArray].length - 1) {
                AllArrays[pArray][inx] = AllArrays[pArray][inx + 1];
                AllArrays[pArray][inx + 1] = thCell;
            }
            darray = AllArrays[pArray];
            swimCllesMerge();
            updateCellChledrens(thisCell.parent);
            G.getSelectionModel().clear();
        }



    };
    this.swimToLeft = function() {
        var cells = G.getSelectionCells();
        var thisCell = cells[0];
        if (isSwimLane(thisCell)) {

            var thCell = thisCell.getId();
            var pArray = getCellArray(thCell);
            var inx = AllArrays[pArray].indexOf(thCell);
            if (inx > 0) {
                AllArrays[pArray][inx] = AllArrays[pArray][inx - 1];
                AllArrays[pArray][inx - 1] = thCell;
            }
            darray = AllArrays[pArray];
            swimCllesMerge();
            updateCellChledrens(thisCell.parent);
            G.getSelectionModel().clear();
        }

    };
    this.swimtoFirst = function() {
        var cells = G.getSelectionCells();
        var thisCell = cells[0];
        thisCell.value.setAttribute('itemid', "-1");
        if (isSwimLane(thisCell)) {

            var thCell = thisCell.getId();
            var pArray = getCellArray(thCell);
            var inx = AllArrays[pArray].indexOf(thCell);
            if (inx > 0) {
                AllArrays[pArray].splice(inx, 1);
                AllArrays[pArray].unshift(thCell);
            }
            darray = AllArrays[pArray];
            swimCllesMerge();
            G.getSelectionModel().clear();
            updateCellChledrens(thisCell.parent);
        }

    };
    this.swimtoLast = function() {
        var cells = G.getSelectionCells();
        var thisCell = cells[0];
        thisCell.value.setAttribute('itemid', "-1");
        if (isSwimLane(thisCell)) {

            var thCell = thisCell.getId();
            var pArray = getCellArray(thCell);
            var inx = AllArrays[pArray].indexOf(thCell);
            if (inx >= 0) {

                AllArrays[pArray].push(thCell);
                AllArrays[pArray].splice(inx, 1);
            }
            darray = AllArrays[pArray];
            swimCllesMerge();
            updateCellChledrens(thisCell.parent);
            G.getSelectionModel().clear();
        }

    };
    this.addChild = function() {

        var cells = G.getSelectionCells();
        var ecall = cells[0];
        ecall.value.setAttribute('itemid', "-1");
        if (isSwimLane(ecall)) {

            addFromStatus = "1";


            var thgeo = ecall.getGeometry();
            var addcell = this.createV(ecall, null, myType, 0, 0, thgeo.width, thgeo.height, returnSwimStyle(ecall));




        }

    };
    this.addtoLast = function() {


        var cells = G.getSelectionCells();
        var ecall = cells[0];
        ecall.value.setAttribute('itemid', "-1");
        if (isSwimLane(ecall)) {
            var thCell = ecall.getId();
            var pArray = getCellArray(thCell);
            var thgeo = ecall.getGeometry();
            addStatus = "1";
            var thgeo = ecall.getGeometry();


            var addcell = this.createV(ecall.parent, null, myType, thgeo.x, thgeo.y, thgeo.width, thgeo.height, returnSwimStyle(ecall));
            AllArrays[pArray].splice(AllArrays[pArray].length, 0, addcell.getId());
            darray = AllArrays[pArray];
            swimCllesMerge();
            updateChSize(ecall);
            addStatus = "0";
            G.getSelectionModel().clear();
        }



    };
    this.addtoFirst = function() {


        var cells = G.getSelectionCells();
        var ecall = cells[0];
        ecall.value.setAttribute('itemid', "-1");
        if (isSwimLane(ecall)) {
            var thCell = ecall.getId();
            var pArray = getCellArray(thCell);
            var thgeo = ecall.getGeometry();
            addStatus = "1";
            var thgeo = ecall.getGeometry();


            var addcell = this.createV(ecall.parent, null, myType, thgeo.x, thgeo.y, thgeo.width, thgeo.height, returnSwimStyle(ecall));
            AllArrays[pArray].splice(0, 0, addcell.getId());
            darray = AllArrays[pArray];
            swimCllesMerge();
            updateChSize(ecall);
            addStatus = "0";
            G.getSelectionModel().clear();
        }



    };
    this.addswimToRight = function() {


        var cells = G.getSelectionCells();

        var ecall = cells[0];
        ecall.value.setAttribute('itemid', "-1");
        if (isSwimLane(ecall)) {
            var thCell = ecall.getId();
            var pArray = getCellArray(thCell);
            var thgeo = ecall.getGeometry();
            addStatus = "1";
            var thgeo = ecall.getGeometry();

            var addcell = this.createV(ecall.parent, null, myType, thgeo.x, thgeo.y, thgeo.width, thgeo.height, returnSwimStyle(ecall));
            AllArrays[pArray].splice(AllArrays[pArray].indexOf(thCell) + 1, 0, addcell.getId());
            darray = AllArrays[pArray];
            swimCllesMerge();
            updateChSize(ecall);
            addStatus = "0";
            G.getSelectionModel().clear();
        }



    };
    this.addswimToLeft = function() {


        var ecall = G.getSelectionCells()[0];
        ecall.value.setAttribute('itemid', "-1");


        if (isSwimLane(ecall)) {
            var thCell = ecall.getId();
            var pArray = getCellArray(thCell);
            var thgeo = ecall.getGeometry();
            addStatus = "1";
            var thgeo = ecall.getGeometry();


            var addcell = this.createV(ecall.parent, null, myType, thgeo.x, thgeo.y, thgeo.width, thgeo.height, returnSwimStyle(ecall));

            if (AllArrays[pArray] != null) {
                var inx = AllArrays[pArray].indexOf(thCell);

                AllArrays[pArray].splice(inx, 0, addcell.getId());
                darray = AllArrays[pArray];

                swimCllesMerge();
                updateChSize(ecall);

                addStatus = "0";
                G.getSelectionModel().clear();
                //  updateCellChledrens(thCell);
                /*
                 
                 */

            }
        }






    };



    function updateattrWithID(parent, itemID, attr, value) {

        var cells = G.getChildCells(parent, true, true);




        for (var i = 0; i < cells.length; i++) {

            if (cells[i] != null) {




                if (isSwimLane(cells[i])) {

                    updateattrWithID(cells[i],itemID,    attr, value);
                } else {


            

                    if (cells[i].getAttribute('itemid', '-1') === itemID) {


                        if (attr === "value") {
                            cells[i].value.setAttribute('label', value);

                        }
                    }
                }


            }
        }

        G.refresh();
    }

//</editor-fold>

//<editor-fold defaultstate="collapsed" desc="EVENTS">

    G.addListener(mxEvent.CHANGE, function(sender, evt) {


    })


    G.addListener(mxEvent.FOLD_CELLS, function(sender, evt)
    {

        statusFroupdatePostion = false;
    })

    G.addListener(mxEvent.CELLS_FOLDED, function(sender, evt)
    {

        statusFroupdatePostion = true;
        var cells = evt.getProperty("cells");
        var type = evt.getProperty("collapse");

        if (isSwimLane(cells[0])) {

            updateArray(cells[0].getId());
            if (type == true) {

                swimCllesCollapse(true);


            } else {
                swimCllesCollapse(false);


            }
        }

        swimCllesUpdateSize(cells[0]);




    }
    )

    G.addListener(mxEvent.CLICK, function(sender, evt)
    {
        var cell = evt.getProperty('cell');


        if (cell != null)
        {

        }

    });

    G.addListener(mxEvent.CELLS_MOVED, function(sender, evt)
    {




        var cells = evt.getProperty('cells');
        if (isSwimLane(cells[0])) {
            updateArray(cells[0].getId());
            if (darray.length > 1) {
                darray = swimCllesOrder();
                updateCellChledrens(cells[0].parent);
                swimCllesMerge();


            }

        }

        updatePostion(cells[0]);
    });



    G.addListener(mxEvent.LABEL_CHANGED, function(sender, evt)
    {


        var cells = G.getSelectionCells();

        if (cells.length > 0) {
            if (cells[0].getAttribute('itemid', '-1') != '-1') {


                updateattrWithID(G.getModel().getParent(), cells[0].getAttribute('itemid', '-1'), "value", cells[0].getAttribute('label', '-1'))



            }
        }


    })
    G.addListener(mxEvent.CELLS_RESIZED, function(sender, evt)
    {



        var cells = evt.getProperty('cells');
        if (isSwimLane(cells[0])) {
            if (cells[0] != null)
            {
                updateArray(cells[0].getId());
                RESIZEDUpdate(cells[0]);


                swimCllesUpdateSize(cells[0]);
                updateCellChledrens(cells[0].parent);




            }
        }
    })


    G.addListener(mxEvent.CELLS_REMOVED, function(sender, evt)
    {
        var cells = evt.getProperty("cells");
        updateArray(cells[0].getId());
        removeFromArray(cells[0].getId());


        var tCell = G.getModel().getCell(darray[0]);
        if (tCell != null) {
            updateCellChledrens(tCell.parent);
        }
        swimCllesMerge();

        /*
         alert (cells[0].parent.getId());
         updateCellChledrens(cells[0].parent);*/
    });
    G.addListener(mxEvent.CELLS_ADDED, function(sender, evt)
    {
        var cells = evt.getProperty("cells");


        if (isSwimLane(cells[0])) {




            AddCellArry(cells[0]);


        }
        updatePostion(cells[0]);
    });





    var editor = this;

    function AddCellArry(cell) {




        if (isSwimLane(cell)) {



            if (isInCellArray(cell.getId()) == false && addStatus == "0") {




                if (isSwimLane(cell.parent)) {

                    if (addFromStatus != "0" || editor.addFromStatus != "0") {

                        if (isclear(cell.parent)) {

                            var chcels = G.getChildVertices(cell.parent);
                            //alert ()
                            if (chcels.length > 1) {


                                var pArray = getCellArray(chcels[0].getId());
                                if (pArray == null) {

                                    pArray = createArray();
                                }

                                AllArrays[pArray].push(cell.getId());
                            } else {
                                var arid = createArray();
                                AllArrays[arid].push(cell.getId());
                            }

                            updateCellChledrens(cell.parent);


                        } else {
                            var cells = G.getSelectionCells();

                            var cells = G.getChildCells(cell.parent, true, true);

                            for (var i = 0; i < cells.length; i++)
                            {
                                if (isSwimLane(cells[i])) {

                                    G.getModel().remove(cells[i]);
                                }

                            }



                            alert("Error: A child could not be added because a shape exists in this column.");


                        }

                        addFromStatus = "0";


                    } else {

                        G.getModel().remove(cell);

                        alert("Error: Operation not allowed. To add a child click on Add Child option in the right click menu.");
                        //  editor.undoManager.undo();

                    }
                } else {


                    var pArray = getparentArrya(cell);
                    if (pArray != null) {

                        AllArrays[pArray].push(cell.getId());
                    } else {

                        var arid = createArray();
                        AllArrays[arid].push(cell.getId());
                    }
                    updateArray(cell.getId());
                    swimCllesMerge();
                    var tCell = G.getModel().getCell(darray[0]);
                    swimCllesUpdateSize(tCell);
                }
                addFromStatus = "0";
            }


            //  alert(AllArrays);

        }



    }
//</editor-fold>


// Installs dialog if browser window is closed without saving
// This must be disabled during save and image export
    window.onbeforeunload = mxUtils.bind(this, function()
    {
        if (this.modified)
        {
            return mxResources.get('allChangesLost');
        }
    });
// Sets persistent graph state defaults
    this.graph.resetViewOnRootChange = false;
    this.graph.scrollbars = true;
    this.graph.background = null;
}
;
// Editor inherits from mxEventSource
mxUtils.extend(Editor, mxEventSource);
/**
 * Specifies the image URL to be used for the grid.
 */
Editor.prototype.gridImage = IMAGE_PATH + '/grid.gif';
/**
 * Specifies the image URL to be used for the transparent background.
 */
Editor.prototype.transparentImage = IMAGE_PATH + '/transparent.gif';
/**
 * Sets the XML node for the current diagram.
 */
Editor.prototype.setGraphXml = function(node)
{
    var dec = new mxCodec(node.ownerDocument);
    // Preparations for wrapped graph models in case of cached clients.
    // This will read the first mxGraphModel found inside the wrapper.
    if (node.nodeName != 'mxGraphModel')
    {
        var nodes = node.getElementsByTagName('mxGraphModel');
        if (nodes != null && nodes.length > 0)
        {
            node = nodes[0];
        }
    }

    if (node.nodeName == 'mxGraphModel')
    {
        this.graph.view.scale = 1;
        this.graph.gridEnabled = node.getAttribute('grid') != '0';
        this.graph.graphHandler.guidesEnabled = node.getAttribute('guides') != '0';
        this.graph.setTooltips(node.getAttribute('tooltips') != '0');
        this.graph.setConnectable(node.getAttribute('connect') != '0');
        this.graph.foldingEnabled = node.getAttribute('fold') != '0';
        this.graph.scrollbars = node.getAttribute('scrollbars') != '0';
        if (!this.graph.scrollbars)
        {
            this.graph.container.scrollLeft = 0;
            this.graph.container.scrollTop = 0;
            this.graph.view.translate.x = Number(node.getAttribute('dx') || 0);
            this.graph.view.translate.y = Number(node.getAttribute('dy') || 0);
        }

        this.graph.pageVisible = node.getAttribute('page') == '1';
        this.graph.pageBreaksVisible = this.graph.pageVisible;
        this.graph.preferPageSize = this.graph.pageBreaksVisible;
        // Loads the persistent state settings
        var ps = node.getAttribute('pageScale');
        if (ps != null)
        {
            this.graph.pageScale = ps;
        }
        else
        {
            this.graph.pageScale = 1.5;
        }

        var pw = node.getAttribute('pageWidth');
        var ph = node.getAttribute('pageHeight');
        if (pw != null && ph != null)
        {
            this.graph.pageFormat = new mxRectangle(0, 0, parseFloat(pw), parseFloat(ph));
            this.outline.outline.pageFormat = this.graph.pageFormat;
        }

        // Loads the persistent state settings
        var bg = node.getAttribute('background');
        if (bg != null && bg.length > 0)
        {
            this.graph.background = bg;
        }

        dec.decode(node, this.graph.getModel());
        this.updateGraphComponents();
    }
    else
    {
        // Workaround for invalid XML output in Firefox 20 due to bug in mxUtils.getXml
        var wrapper = dec.document.createElement('mxGraphModel');
        wrapper.appendChild(node);
        dec.decode(wrapper, this.graph.getModel());
        this.updateGraphComponents();
    }
};
/**
 * Returns the XML node that represents the current diagram.
 */
Editor.prototype.getGraphXml = function()
{
    var enc = new mxCodec(mxUtils.createXmlDocument());
    var node = enc.encode(this.graph.getModel());
    if (this.graph.view.translate.x != 0 || this.graph.view.translate.y != 0)
    {
        node.setAttribute('dx', Math.round(this.graph.view.translate.x * 100) / 100);
        node.setAttribute('dy', Math.round(this.graph.view.translate.y * 100) / 100);
    }

    node.setAttribute('grid', (this.graph.isGridEnabled()) ? '1' : '0');
    node.setAttribute('guides', (this.graph.graphHandler.guidesEnabled) ? '1' : '0');
    node.setAttribute('guides', (this.graph.graphHandler.guidesEnabled) ? '1' : '0');
    node.setAttribute('tooltips', (this.graph.tooltipHandler.isEnabled()) ? '1' : '0');
    node.setAttribute('connect', (this.graph.connectionHandler.isEnabled()) ? '1' : '0');
    node.setAttribute('fold', (this.graph.foldingEnabled) ? '1' : '0');
    node.setAttribute('page', (this.graph.pageVisible) ? '1' : '0');
    node.setAttribute('pageScale', this.graph.pageScale);
    node.setAttribute('pageWidth', this.graph.pageFormat.width);
    node.setAttribute('pageHeight', this.graph.pageFormat.height);
    if (!this.graph.scrollbars)
    {
        node.setAttribute('scrollbars', '0');
    }

    if (this.graph.background != null)
    {
        node.setAttribute('background', this.graph.background);
    }

    return node;
};
/**
 * Keeps the graph container in sync with the persistent graph state
 */
Editor.prototype.updateGraphComponents = function()
{
    var graph = this.graph;
    var outline = this.outline;
    if (graph.container != null && outline.outline.container != null)
    {
        if (graph.background != null)
        {
            if (graph.background == 'none')
            {
                graph.container.style.backgroundColor = 'transparent';
            }
            else
            {
                if (graph.view.backgroundPageShape != null)
                {
                    graph.view.backgroundPageShape.fill = graph.background;
                    graph.view.backgroundPageShape.reconfigure();
                }

                graph.container.style.backgroundColor = graph.background;
            }
        }
        else
        {
            graph.container.style.backgroundColor = '';
        }

        if (graph.pageVisible)
        {
            graph.container.style.backgroundColor = '#ebebeb';
            graph.container.style.borderStyle = 'solid';
            graph.container.style.borderColor = '#e5e5e5';
            graph.container.style.borderTopWidth = '1px';
            graph.container.style.borderLeftWidth = '1px';
            graph.container.style.borderRightWidth = '0px';
            graph.container.style.borderBottomWidth = '0px';
        }
        else
        {
            graph.container.style.border = '';
        }

        outline.outline.container.style.backgroundColor = graph.container.style.backgroundColor;
        if (outline.outline.pageVisible != graph.pageVisible ||
                outline.outline.pageScale != graph.pageScale)
        {
            outline.outline.pageScale = graph.pageScale;
            outline.outline.pageVisible = graph.pageVisible;
            outline.outline.view.validate();
        }

        if (graph.scrollbars && graph.container.style.overflow == 'hidden' && !touchStyle)
        {
            graph.container.style.overflow = 'auto';
        }
        else if (!graph.scrollbars || touchStyle)
        {
            graph.container.style.overflow = 'hidden';
        }

        // Transparent.gif is a workaround for focus repaint problems in IE
        var noBackground = (mxClient.IS_IE && document.documentMode >= 9) ? 'url(' + this.transparentImage + ')' : 'none';
        graph.container.style.backgroundImage = (!graph.pageVisible && graph.isGridEnabled()) ? 'url(' + this.gridImage + ')' : noBackground;
        if (graph.view.backgroundPageShape != null)
        {
            graph.view.backgroundPageShape.node.style.backgroundImage = (this.graph.isGridEnabled()) ? 'url(' + this.gridImage + ')' : 'none';
        }
    }
};
/**
 * Initializes the environment.
 */
Editor.prototype.init = function()
{
    // Adds stylesheet for IE6
    if (mxClient.IS_IE6)
    {
        mxClient.link('stylesheet', CSS_PATH + '/grapheditor-ie6.css');
    }

    // Adds required resources (disables loading of fallback properties, this can only
    // be used if we know that all keys are defined in the language specific file)
    mxResources.loadDefaultBundle = false;
    mxResources.add(RESOURCE_BASE);
    // Makes the connection hotspot smaller
    mxConstants.DEFAULT_HOTSPOT = 0.3;
    var mxConnectionHandlerCreateMarker = mxConnectionHandler.prototype.createMarker;
    mxConnectionHandler.prototype.createMarker = function()
    {
        var marker = mxConnectionHandlerCreateMarker.apply(this, arguments);
        // Overrides to ignore hotspot only for target terminal
        marker.intersects = mxUtils.bind(this, function(state, evt)
        {
            if (this.isConnecting())
            {
                return true;
            }

            return mxCellMarker.prototype.intersects.apply(marker, arguments);
        });
        return marker;
    };
    // Makes the shadow brighter
    mxConstants.SHADOWCOLOR = '#d0d0d0';
    // Changes some default colors
    mxConstants.HANDLE_FILLCOLOR = '#99ccff';
    mxConstants.HANDLE_STROKECOLOR = '#0088cf';
    mxConstants.VERTEX_SELECTION_COLOR = '#00a8ff';
    mxConstants.OUTLINE_COLOR = '#00a8ff';
    mxConstants.OUTLINE_HANDLE_FILLCOLOR = '#99ccff';
    mxConstants.OUTLINE_HANDLE_STROKECOLOR = '#00a8ff';
    mxConstants.CONNECT_HANDLE_FILLCOLOR = '#cee7ff';
    mxConstants.EDGE_SELECTION_COLOR = '#00a8ff';
    mxConstants.DEFAULT_VALID_COLOR = '#00a8ff';
    mxConstants.LABEL_HANDLE_FILLCOLOR = '#cee7ff';
    mxConstants.GUIDE_COLOR = '#0088cf';
    mxGraph.prototype.pageBreakColor = '#c0c0c0';
    mxGraph.prototype.pageScale = 1;
    // Increases default rubberband opacity (default is 20)
    mxRubberband.prototype.defaultOpacity = 30;
    // Changes border color of background page shape
    mxGraphView.prototype.createBackgroundPageShape = function(bounds)
    {
        return new mxRectangleShape(bounds, this.graph.background || 'white', '#cacaca');
    };
    // Fits the number of background pages to the graph
    mxGraphView.prototype.getBackgroundPageBounds = function()
    {
        var gb = this.getGraphBounds();
        // Computes unscaled, untranslated graph bounds
        var x = (gb.width > 0) ? gb.x / this.scale - this.translate.x : 0;
        var y = (gb.height > 0) ? gb.y / this.scale - this.translate.y : 0;
        var w = gb.width / this.scale;
        var h = gb.height / this.scale;
        var fmt = this.graph.pageFormat;
        var ps = this.graph.pageScale;
        var pw = fmt.width * ps;
        var ph = fmt.height * ps;
        var x0 = Math.floor(Math.min(0, x) / pw);
        var y0 = Math.floor(Math.min(0, y) / ph);
        var xe = Math.ceil(Math.max(1, x + w) / pw);
        var ye = Math.ceil(Math.max(1, y + h) / ph);
        var rows = xe - x0;
        var cols = ye - y0;
        var bounds = new mxRectangle(this.scale * (this.translate.x + x0 * pw), this.scale *
                (this.translate.y + y0 * ph), this.scale * rows * pw, this.scale * cols * ph);
        return bounds;
    };
    // Add panning for background page in VML
    var graphPanGraph = mxGraph.prototype.panGraph;
    mxGraph.prototype.panGraph = function(dx, dy)
    {
        graphPanGraph.apply(this, arguments);
        if ((this.dialect != mxConstants.DIALECT_SVG && this.view.backgroundPageShape != null) &&
                (!this.useScrollbarsForPanning || !mxUtils.hasScrollbars(this.container)))
        {
            this.view.backgroundPageShape.node.style.marginLeft = dx + 'px';
            this.view.backgroundPageShape.node.style.marginTop = dy + 'px';
        }
    };
    // Adds pinch support for background page
    // TODO: Scale background page on iOS
    /*var panningHandlerScaleGraph = mxPanningHandler.prototype.scaleGraph;
     mxPanningHandler.prototype.scaleGraph = function(scale, preview)
     {
     panningHandlerScaleGraph.apply(this, arguments);
     
     var shape = this.graph.view.backgroundPageShape;
     
     if (shape != null)
     {
     if (preview)
     {
     shape.node.style[mxClient.CSS_PREFIX + 'Transform'] = 'scale(' + scale + ')';
     }
     else
     {
     shape.node.style[mxClient.CSS_PREFIX + 'Transform'] = '';
     }
     
     mxLog.debug('style', shape.node.style[mxClient.CSS_PREFIX + 'Transform'],
     shape.node.style.left);
     }
     };*/

    var editor = this;
    // Uses HTML for background pages (to support grid background image)
    mxGraphView.prototype.validateBackground = function()
    {
        var bg = this.graph.getBackgroundImage();
        if (bg != null)
        {
            if (this.backgroundImage == null || this.backgroundImage.image != bg.src)
            {
                if (this.backgroundImage != null)
                {
                    this.backgroundImage.destroy();
                }

                var bounds = new mxRectangle(0, 0, 1, 1);
                this.backgroundImage = new mxImageShape(bounds, bg.src);
                this.backgroundImage.dialect = this.graph.dialect;
                this.backgroundImage.init(this.backgroundPane);
                this.backgroundImage.redraw();
            }

            this.redrawBackgroundImage(this.backgroundImage, bg);
        }
        else if (this.backgroundImage != null)
        {
            this.backgroundImage.destroy();
            this.backgroundImage = null;
        }

        if (this.graph.pageVisible)
        {
            var bounds = this.getBackgroundPageBounds();
            if (this.backgroundPageShape == null)
            {
                this.backgroundPageShape = this.createBackgroundPageShape(bounds);
                this.backgroundPageShape.scale = 1;
                this.backgroundPageShape.isShadow = true;
                this.backgroundPageShape.dialect = mxConstants.DIALECT_STRICTHTML;
                this.backgroundPageShape.init(this.graph.container);
                // Required for the browser to render the background page in correct order
                this.graph.container.firstChild.style.position = 'absolute';
                this.graph.container.insertBefore(this.backgroundPageShape.node, this.graph.container.firstChild);
                this.backgroundPageShape.redraw();
                this.backgroundPageShape.node.className = 'geBackgroundPage';
                this.backgroundPageShape.node.style.backgroundPosition = '-1px -1px';
                // Adds listener for double click handling on background
                mxEvent.addListener(this.backgroundPageShape.node, 'dblclick',
                        mxUtils.bind(this, function(evt)
                        {
                            this.graph.dblClick(evt);
                        })
                        );
                // Adds basic listeners for graph event dispatching outside of the
                // container and finishing the handling of a single gesture
                mxEvent.addGestureListeners(this.backgroundPageShape.node,
                        mxUtils.bind(this, function(evt)
                        {
                            this.graph.fireMouseEvent(mxEvent.MOUSE_DOWN, new mxMouseEvent(evt));
                        }),
                        mxUtils.bind(this, function(evt)
                        {
                            // Hides the tooltip if mouse is outside container
                            if (this.graph.tooltipHandler != null &&
                                    this.graph.tooltipHandler.isHideOnHover())
                            {
                                this.graph.tooltipHandler.hide();
                            }

                            if (this.graph.isMouseDown &&
                                    !mxEvent.isConsumed(evt))
                            {
                                this.graph.fireMouseEvent(mxEvent.MOUSE_MOVE,
                                        new mxMouseEvent(evt));
                            }
                        }),
                        mxUtils.bind(this, function(evt)
                        {
                            this.graph.fireMouseEvent(mxEvent.MOUSE_UP,
                                    new mxMouseEvent(evt));
                        }));
            }
            else
            {
                this.backgroundPageShape.scale = 1;
                this.backgroundPageShape.bounds = bounds;
                this.backgroundPageShape.redraw();
            }

            this.backgroundPageShape.node.style.backgroundImage = (this.graph.isGridEnabled()) ?
                    'url(' + editor.gridImage + ')' : 'none';
        }
        else if (this.backgroundPageShape != null)
        {
            this.backgroundPageShape.destroy();
            this.backgroundPageShape = null;
        }
    };
    // Draws page breaks only within the page
    mxGraph.prototype.updatePageBreaks = function(visible, width, height)
    {
        var scale = this.view.scale;
        var tr = this.view.translate;
        var fmt = this.pageFormat;
        var ps = scale * this.pageScale;
        var bounds2 = this.view.getBackgroundPageBounds();
        width = bounds2.width;
        height = bounds2.height;
        var bounds = new mxRectangle(scale * tr.x, scale * tr.y,
                fmt.width * ps, fmt.height * ps);
        // Does not show page breaks if the scale is too small
        visible = visible && Math.min(bounds.width, bounds.height) > this.minPageBreakDist;
        var horizontalCount = (visible) ? Math.ceil(width / bounds.width) - 1 : 0;
        var verticalCount = (visible) ? Math.ceil(height / bounds.height) - 1 : 0;
        var right = bounds2.x + width;
        var bottom = bounds2.y + height;
        if (this.horizontalPageBreaks == null && horizontalCount > 0)
        {
            this.horizontalPageBreaks = [];
        }

        if (this.horizontalPageBreaks != null)
        {
            for (var i = 0; i <= horizontalCount; i++)
            {
                var pts = [new mxPoint(bounds2.x + (i + 1) * bounds.width, bounds2.y),
                    new mxPoint(bounds2.x + (i + 1) * bounds.width, bottom)];
                if (this.horizontalPageBreaks[i] != null)
                {
                    this.horizontalPageBreaks[i].scale = 1;
                    this.horizontalPageBreaks[i].points = pts;
                    this.horizontalPageBreaks[i].redraw();
                }
                else
                {
                    var pageBreak = new mxPolyline(pts, this.pageBreakColor, this.scale);
                    pageBreak.dialect = this.dialect;
                    pageBreak.isDashed = this.pageBreakDashed;
                    pageBreak.addPipe = false;
                    pageBreak.scale = scale;
                    pageBreak.init(this.view.backgroundPane);
                    pageBreak.redraw();
                    this.horizontalPageBreaks[i] = pageBreak;
                }
            }

            for (var i = horizontalCount; i < this.horizontalPageBreaks.length; i++)
            {
                this.horizontalPageBreaks[i].destroy();
            }

            this.horizontalPageBreaks.splice(horizontalCount, this.horizontalPageBreaks.length - horizontalCount);
        }

        if (this.verticalPageBreaks == null && verticalCount > 0)
        {
            this.verticalPageBreaks = [];
        }

        if (this.verticalPageBreaks != null)
        {
            for (var i = 0; i <= verticalCount; i++)
            {
                var pts = [new mxPoint(bounds2.x, bounds2.y + (i + 1) * bounds.height),
                    new mxPoint(right, bounds2.y + (i + 1) * bounds.height)];
                if (this.verticalPageBreaks[i] != null)
                {
                    this.verticalPageBreaks[i].scale = 1; //scale;
                    this.verticalPageBreaks[i].points = pts;
                    this.verticalPageBreaks[i].redraw();
                }
                else
                {
                    var pageBreak = new mxPolyline(pts, this.pageBreakColor, scale);
                    pageBreak.dialect = this.dialect;
                    pageBreak.isDashed = this.pageBreakDashed;
                    pageBreak.addPipe = false;
                    pageBreak.scale = scale;
                    pageBreak.init(this.view.backgroundPane);
                    pageBreak.redraw();
                    this.verticalPageBreaks[i] = pageBreak;
                }
            }

            for (var i = verticalCount; i < this.verticalPageBreaks.length; i++)
            {
                this.verticalPageBreaks[i].destroy();
            }

            this.verticalPageBreaks.splice(verticalCount, this.verticalPageBreaks.length - verticalCount);
        }
    };
    // Enables snapping to off-grid terminals for edge waypoints
    mxEdgeHandler.prototype.snapToTerminals = true;
    // Enables guides
    mxGraphHandler.prototype.guidesEnabled = true;
    // Disables removing relative children from parents
    var mxGraphHandlerShouldRemoveCellsFromParent = mxGraphHandler.prototype.shouldRemoveCellsFromParent;
    mxGraphHandler.prototype.shouldRemoveCellsFromParent = function(parent, cells, evt)
    {
        for (var i = 0; i < cells.length; i++)
        {
            if (this.graph.getModel().isVertex(cells[i]))
            {
                var geo = this.graph.getCellGeometry(cells[i]);
                if (geo != null && geo.relative)
                {
                    return false;
                }
            }
        }

        return mxGraphHandlerShouldRemoveCellsFromParent.apply(this, arguments);
    };
    // Alt-move disables guides
    mxGuide.prototype.isEnabledForEvent = function(evt)
    {
        return !mxEvent.isAltDown(evt);
    };
    // Consumes click events for disabled menu items
    mxPopupMenuAddItem = mxPopupMenu.prototype.addItem;
    mxPopupMenu.prototype.addItem = function(title, image, funct, parent, iconCls, enabled)
    {
        var result = mxPopupMenuAddItem.apply(this, arguments);
        if (enabled != null && !enabled)
        {
            mxEvent.addListener(result, 'mousedown', function(evt)
            {

                mxEvent.consume(evt);
            });
        }

        return result;
    };
    // Selects descendants before children selection mode
    var graphHandlerGetInitialCellForEvent = mxGraphHandler.prototype.getInitialCellForEvent;
    mxGraphHandler.prototype.getInitialCellForEvent = function(me)
    {
        var model = this.graph.getModel();
        var psel = model.getParent(this.graph.getSelectionCell());
        var cell = graphHandlerGetInitialCellForEvent.apply(this, arguments);
        var parent = model.getParent(cell);
        if (psel == null || (psel != cell && psel != parent))
        {
            while (!this.graph.isCellSelected(cell) && !this.graph.isCellSelected(parent) &&
                    model.isVertex(parent) && !this.graph.isValidRoot(parent))
            {
                cell = parent;
                parent = this.graph.getModel().getParent(cell);
            }
        }

        return cell;
    };
    // Selection is delayed to mouseup if child selected
    var graphHandlerIsDelayedSelection = mxGraphHandler.prototype.isDelayedSelection;
    mxGraphHandler.prototype.isDelayedSelection = function(cell)
    {
        var result = graphHandlerIsDelayedSelection.apply(this, arguments);
        var model = this.graph.getModel();
        var psel = model.getParent(this.graph.getSelectionCell());
        var parent = model.getParent(cell);
        if (psel == null || (psel != cell && psel != parent))
        {
            if (!this.graph.isCellSelected(cell) && model.isVertex(parent) && !this.graph.isValidRoot(parent))
            {
                result = true;
            }
        }

        return result;
    };
    // Delayed selection of parent group
    mxGraphHandler.prototype.selectDelayed = function(me)
    {
        var cell = me.getCell();
        if (cell == null)
        {
            cell = this.cell;
        }

        var model = this.graph.getModel();
        var parent = model.getParent(cell);
        while (this.graph.isCellSelected(cell) && model.isVertex(parent) && !this.graph.isValidRoot(parent))
        {
            cell = parent;
            parent = model.getParent(cell);
        }

        this.graph.selectCellForEvent(cell, me.getEvent());
    };
    // Returns last selected ancestor
    mxPanningHandler.prototype.getCellForPopupEvent = function(me)
    {
        var cell = me.getCell();
        var model = this.graph.getModel();
        var parent = model.getParent(cell);
        while (model.isVertex(parent) && !this.graph.isValidRoot(parent))
        {
            if (this.graph.isCellSelected(parent))
            {
                cell = parent;
            }

            parent = model.getParent(parent);
        }

        return cell;
    };
};
/**     
 * Creates and returns a new undo manager.
 */

this.disableUndo = 0;

var editor = this;
Editor.prototype.createUndoManager = function()
{
    if (editor.disableUndo == 0) {
        var graph = this.graph;
        var undoMgr = new mxUndoManager();
        // Installs the command history
        var listener = function(sender, evt)
        {

            undoMgr.undoableEditHappened(evt.getProperty('edit'));

        };
        graph.getModel().addListener(mxEvent.UNDO, listener);
        graph.getView().addListener(mxEvent.UNDO, listener);
        // Keeps the selection in sync with the history
        var undoHandler = function(sender, evt)
        {
            var cand = graph.getSelectionCellsForChanges(evt.getProperty('edit').changes);
            var cells = [];
            for (var i = 0; i < cand.length; i++)
            {
                if (graph.view.getState(cand[i]) != null)
                {
                    cells.push(cand[i]);
                }
            }

            graph.setSelectionCells(cells);
        }
    }
    ;
    undoMgr.addListener(mxEvent.UNDO, undoHandler);
    undoMgr.addListener(mxEvent.REDO, undoHandler);
    return undoMgr;
};
/**
 * Adds basic stencil set (no namespace).
 */
Editor.prototype.initStencilRegistry = function()
{
    // Loads default stencils
    mxStencilRegistry.loadStencilSet(STENCIL_PATH + '/general.xml');
};
/**
 * Overrides stencil registry for dynamic loading of stencils.
 */
(function()
{
    /**
     * Maps from library names to an array of Javascript filenames,
     * which are synchronously loaded. Currently only stencil files
     * (.xml) and JS files (.js) are supported.
     * IMPORTANT: For embedded diagrams to work entries must also
     * be added in EmbedServlet.java.
     */
    mxStencilRegistry.libraries = {};
    /**
     * Stores all package names that have been dynamically loaded.
     * Each package is only loaded once.
     */
    mxStencilRegistry.packages = [];
    // Extends the default stencil registry to add dynamic loading
    mxStencilRegistry.getStencil = function(name)
    {
        var result = mxStencilRegistry.stencils[name];
        if (result == null)
        {
            var basename = mxStencilRegistry.getBasenameForStencil(name);
            // Loads stencil files and tries again
            if (basename != null)
            {
                var libs = mxStencilRegistry.libraries[basename];
                if (libs != null)
                {
                    if (mxStencilRegistry.packages[basename] == null)
                    {
                        mxStencilRegistry.packages[basename] = 1;
                        for (var i = 0; i < libs.length; i++)
                        {
                            var fname = libs[i];
                            if (fname.toLowerCase().substring(fname.length - 4, fname.length) == '.xml')
                            {
                                mxStencilRegistry.loadStencilSet(fname, null);
                            }
                            else if (fname.toLowerCase().substring(fname.length - 3, fname.length) == '.js')
                            {
                                var req = mxUtils.load(fname);
                                if (req != null)
                                {
                                    eval.call(window, req.getText());
                                }
                            }
                            else
                            {
                                // FIXME: This does not yet work as the loading is triggered after
                                // the shape was used in the graph, at which point the keys have
                                // typically been translated in the calling method.
                                //mxResources.add(fname);
                            }
                        }
                    }
                }
                else
                {
                    mxStencilRegistry.loadStencilSet(STENCIL_PATH + '/' + basename + '.xml', null);
                }

                result = mxStencilRegistry.stencils[name];
            }
        }

        return result;
    };
    // Returns the basename for the given stencil or null if no file must be
    // loaded to render the given stencil.
    mxStencilRegistry.getBasenameForStencil = function(name)
    {
        var parts = name.split('.');
        var tmp = null;
        if (parts.length > 0 && parts[0] == 'mxgraph')
        {
            tmp = parts[1];
            for (var i = 2; i < parts.length - 1; i++)
            {
                tmp += '/' + parts[i];
            }
        }

        return tmp;
    };
    // Loads the given stencil set
    mxStencilRegistry.loadStencilSet = function(stencilFile, postStencilLoad, force)
    {
        force = (force != null) ? force : false;
        // Uses additional cache for detecting previous load attempts
        var xmlDoc = mxStencilRegistry.packages[stencilFile];
        if (force || xmlDoc == null)
        {
            var install = false;
            if (xmlDoc == null)
            {
                var req = mxUtils.load(stencilFile);
                xmlDoc = req.getXml();
                mxStencilRegistry.packages[stencilFile] = xmlDoc;
                install = true;
            }

            mxStencilRegistry.parseStencilSet(xmlDoc, postStencilLoad, install);
        }
    };
    // Parses the given stencil set
    mxStencilRegistry.parseStencilSet = function(xmlDocument, postStencilLoad, install)
    {
        install = (install != null) ? install : true;
        var root = xmlDocument.documentElement;
        var shape = root.firstChild;
        var packageName = '';
        var name = root.getAttribute('name');
        if (name != null)
        {
            packageName = name + '.';
        }

        while (shape != null)
        {
            if (shape.nodeType == mxConstants.NODETYPE_ELEMENT)
            {
                name = shape.getAttribute('name');
                if (name != null)
                {
                    packageName = packageName.toLowerCase();
                    var stencilName = name.replace(/ /g, "_");
                    if (install)
                    {
                        mxStencilRegistry.addStencil(packageName + stencilName.toLowerCase(), new mxStencil(shape));
                    }

                    if (postStencilLoad != null)
                    {
                        var w = shape.getAttribute('w');
                        var h = shape.getAttribute('h');
                        w = (w == null) ? 80 : parseInt(w, 10);
                        h = (h == null) ? 80 : parseInt(h, 10);
                        postStencilLoad(packageName, stencilName, name, w, h);
                    }
                }
            }

            shape = shape.nextSibling;
        }
    };
})();
/**
 * Class for asynchronously opening a new window and loading a file at the same
 * time. This acts as a bridge between the open dialog and the new editor.
 */
OpenFile = function(done)
{
    this.producer = null;
    this.consumer = null;
    this.done = done;
};
/**
 * Registers the editor from the new window.
 */
OpenFile.prototype.setConsumer = function(value)
{
    this.consumer = value;
    this.execute();
};
/**
 * Sets the data from the loaded file.
 */
OpenFile.prototype.setData = function(value, filename)
{
    this.data = value;
    this.filename = filename;
    this.execute();
};
/**
 * Displays an error message.
 */
OpenFile.prototype.error = function(msg)
{
    this.cancel();
    mxUtils.alert(msg);
};
/**
 * Consumes the data.
 */
OpenFile.prototype.execute = function()
{
    if (this.consumer != null && this.data != null)
    {
        this.consumer(this.data, this.filename);
        this.cancel();
    }
};
/**
 * Cancels the operation.
 */
OpenFile.prototype.cancel = function()
{
    if (this.done != null)
    {
        this.done();
    }
}
;
